// 编写高质量代码：改善JavaScript程序建议--函数式编程

console.log('start')
//惰性函数载入
function fn(index) {
  var f
  switch (index) {
    case 1:
      f = function() {
        console.log('Hello')
      }
      break
    case 2:
      f = function() {
        console.log('Something!')
      }
      break
    case 3:
      f = function() {
        console.log('你好')
      }
      break
    default:
      break
  }
  return f()
}

fn(2)

console.log('end')

// 惰性函数求值

// 常规方式
var t
function f1() {
  t = t ? t : new Date()
  return t
}

console.log('f1:', f1())

// 闭包方式
var f2 = (function() {
  var t = new Date()

  f2 = function() {
    return t
  }

  return f2()
})()

console.log('f2:', f2())

//惰性方式，无需每次求值
var f3 = function() {
  var t = new Date()
  f3 = function() {
    return t
  }

  return f3()
}

console.log('f3:', f3())

///////////////////////////////////////////////////
// 重视函数节流
// function throttle(method, context) {
//   clearTimeout(method.tId)
//   method.iId = setTimeout(function() {
//     method.call(context)
//   }, 1000)
// }

function resize(params) {
  console.log(window.innerWidth)
}

//  window.onresize = function(params) {
//    throttle(resize);  //注意，必须是具名函数
//  }

/**
 * 节流函数(简易)
 * @param now 当前毫秒值
 * @param method 方法
 * @param context 上下文
 */ 
function throttle_1(now, method, context) { 
  var time = +new Date(); 
  throttle_1 = function(now, method, context){ 
    if(now - time > 1000){ 
      time = now; // 更新time 
      method.call(context); 
    } 
  }; 
  throttle_1(now, method, context); 
} 

function resize() { 
  console.log(1);
} 
window.onresize = function() { 
  throttle_1(+new Date(), resize, null); 
}


/////////////////////////////////////////////////////////////////
// 比价函数调用和引用的本质
// 引用函数，多个变量存储的是函数的相同入口指针（地址）。
// 调用函数，执行该函数把返回“值”传递给变量，而不是函数的入口指针（地址）。

// 示例： 函数引用
function f3() {
  var x = 5;
  return x;
}

var f4 = f3;
var f5 = f3;
console.log(f4 === f5);     // true

// 示例： 函数调用
function f10() {
  var x = 5;
  return function() { //返回存储在不同变量中，它们的地址指针完全不一样
    return x;
  }
}

var f11 = f10();    // f11 = function(){ return x; }
var f12 = f10();    // f12 = function(){ return x; }
console.log(f11 === f12); // false


////////////////////////////////////////
// 使用必报化跨作用域开发
// 闭包结构的两个特性：
// （1）封闭性，外界无法访问闭包内部的数据，如果在闭包内声明变量，外界是无法访问的，除非闭包主动向外界提供访问接口。
// （2）持久性，对于一般函数来说，在调用完毕后，系统自动注销函数，而对于闭包来说，在外部函数调用之后，闭包结构依然保存在系统中，闭包中的数据依然存在，从而实现对数据的持久使用。
// 示例：使用闭包结构能够跟踪动态环境中数据的实时变化，并即时存储

function f20(x) {
  var a = x;
  var innerFunc = function() {
    return a;
  }
  a++;
  return innerFunc;
}

var f21 = f20(5);  // f21 = function(){ return a; }
console.log(f21());

////////////////////////////////////////
// 推荐动态调用函数
// 使用call和apply方法可以把一个函数转换为方法传递给某个对象。这种行为只是临时的，函数最终并没有作为对象的方法而存在，当函数被调用后，该对象方法会自动被注销。
var arr = [1, 5, 3];
var m = Math.max.apply(null, arr);
console.log('max in arr: ', m);